/*
 * ============================================================================
 *
 *  [THC RPG] Total HardCore RPG
 *
 *  File:          helpers.inc
 *  Type:          Core
 *  Description:   contains helper functions for the whole project
 *
 *  Copyright (C) 2009-2011  ArsiRC
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * ============================================================================
 */

#pragma semicolon 1

#include <sdktools>

InitOffsets()
{
    ColorOffset=FindSendPropOffs("CAI_BaseNPC","m_clrRender");
    if(ColorOffset==-1)
        SetFailState("[THC RPG] Couldnt find the Color offset");

    GetVelocityOffset_0=FindSendPropOffs("CBasePlayer","m_vecVelocity[0]");
    if(GetVelocityOffset_0==-1)
        SetFailState("[THC RPG] Couldnt find the GetVelocity_0 offset");

    GetVelocityOffset_1=FindSendPropOffs("CBasePlayer","m_vecVelocity[1]");
    if(GetVelocityOffset_1==-1)
        SetFailState("[THC RPG] Couldnt find the GetVelocity_1 offset");

    BaseVelocityOffset=FindSendPropOffs("CBasePlayer","m_vecBaseVelocity");
    if(BaseVelocityOffset==-1)
        SetFailState("[THC RPG] Couldnt find the BaseVelocity offset");

    ActiveWeaponOffset=FindSendPropOffs("CAI_BaseNPC", "m_hActiveWeapon");
    if(ActiveWeaponOffset==-1)
        SetFailState("[THC RPG] Couldnt find the ActiveWeapon offset");

    WeaponClipOffset=FindSendPropOffs("CBaseCombatWeapon", "m_iClip1");
    if(WeaponClipOffset==-1)
        SetFailState("[THC RPG] Couldnt find the WeaponClip offset");

    ArmorOffset=FindSendPropOffs("CCSPlayer","m_ArmorValue");
    if(ArmorOffset==-1)
        SetFailState("[THC RPG] Couldnt find the Armor offset");

    AmmoOffset=FindSendPropOffs("CCSPlayer","m_iAmmo");
    if(AmmoOffset==-1)
        SetFailState("[THC RPG] Couldnt find the Ammo offset");
}

FindMatchingPlayers(const String:matchstr[],clients[])
{
    new count=0;
    if(StrEqual(matchstr,"@all",false))
    {
        for(new x=1;x<=MaxClients;x++)
        {
            if(IsClientInGame(x))
            {
                clients[count]=x;
                count++;
            }
        }
    }
    else if(StrEqual(matchstr,"@t",false))
    {
        for(new x=1;x<=MaxClients;x++)
        {
            if(IsClientInGame(x)&&GetClientTeam(x)==2)
            {
                clients[count]=x;
                count++;
            }
        }
    }
    else if(StrEqual(matchstr,"@ct",false))
    {
        for(new x=1;x<=MaxClients;x++)
        {
            if(IsClientInGame(x)&&GetClientTeam(x)==3)
            {
                clients[count]=x;
                count++;
            }
        }
    }
    else if(matchstr[0]=='@')
    {
        new userid=StringToInt(matchstr[1]);
        if(userid)
        {
            new index=GetClientOfUserId(userid);
            if(index)
            {
                if(IsClientInGame(index))
                {
                    clients[count]=index;
                    count++;
                }
            }
        }
    }
    else
    {
        for(new x=1;x<=MaxClients;x++)
        {
            if(IsClientInGame(x))
            {
                decl String:name[64];
                GetClientName(x,name,sizeof(name));
                if(StrContains(name,matchstr,false)!=-1)
                {
                    clients[count]=x;
                    count++;
                }
            }
        }
    }
    return count;
}

TeamWinXP(client,team)
{
    if(client&&g_CoreConfigCache[CoreConfig_freeforall]==0)
    {
        for(new x=1;x<=MaxClients;x++)
        {
            if(IsClientInGame(x))
            {
                if(x!=client&&IsPlayerAlive(client)&&GetClientTeam(x)==team)
                {
                    SetXP(x,RoundToNearest(TeamRatio(team)*float(GetReqXP(x))*g_CoreConfigCache[CoreConfig_exp_teamwin]),true);
                }
            }
        }
        return 1;
    }
    else
        return -1;
}

Float:TeamRatio(team)
{
    new ttotal;
    new cttotal;
    for(new x=1;x<=MaxClients;x++)
    {
        if(IsClientInGame(x))
        {
            if(IsPlayerAlive(x))
            {
                if(GetClientTeam(x)==2)
                    ttotal++;
                else if(GetClientTeam(x)==3)
                    cttotal++;
            }
        }
    }

    new Float:ratio;
    if(team==2)
        ratio = float(cttotal)/float(ttotal);
    else
        ratio = float(ttotal)/float(cttotal);

    if(ratio<=0.1)
        ratio = 0.1;

    return ratio;
}

CountHumans()
{
    new total=0;
    for(new x=1;x<=MaxClients;x++)
    {
        if(IsClientInGame(x))
        {
            if(GetClientTeam(x)==2||GetClientTeam(x)==3)
            {
                decl String:steamid[64];
                GetClientAuthString(x,steamid,sizeof(steamid));
                if(!StrEqual(steamid,"BOT",false))
                    total++;
            }
        }
    }
    return total;
}

UniqueID(client, String:authid[], maxlen)
{
    if(client)
    {
        new exists=GetClientAuthString(client,authid,maxlen);
        if(exists)
        {
            if(StrEqual(authid,"BOT",true))
            {
                decl String:name[64];
                GetClientName(client,name,sizeof(name));
                Format(authid,maxlen,"BOT_%s",name);
            }
            if(StrEqual(authid,"STEAM_ID_LAN",true))
                GetClientName(client,authid,maxlen);
            return 1;
        }
        else
            return -1;
    }
    else
        return -1;
}

SetSpawnHealth(client,amount)
{
    if(client)
    {
        if(amount<0)
            amount=0;
        clientSpawnHealth[client]=amount;
        return 1;
    }
    else
        return -1;
}

GetSpawnHealth(client)
{
    if(client)
    {
        new returnhealth=clientSpawnHealth[client];
        if(returnhealth<=0)
            returnhealth=100;
        return returnhealth;
    }
    else
        return -1;
}

SetSpawnSpeed(client,Float:amount)
{
    if(client)
    {
        if(amount<=0.0)
            amount=1.0;
        clientSpawnSpeed[client]=amount;
        return 1;
    }
    else
        return -1;
}

Float:GetSpawnSpeed(client)
{
    if(client)
    {
        new Float:returnspeed=clientSpawnSpeed[client];
        if(returnspeed<=0.0)
            returnspeed=1.0;
        return returnspeed;
    }
    else
        return -1.0;
}

Float:CreateVecFromPoints(Float:vec1[3],Float:vec2[3],Float:output[3])
{
    output[0]=vec2[0]-vec1[0];
    output[1]=vec2[1]-vec1[1];
    output[2]=vec2[2]-vec1[2];
}

Normalize(Float:vec[3],Float:output[3])
{
    new Float:scalar=SquareRoot(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
    output[0]=vec[0]/scalar;
    output[1]=vec[1]/scalar;
    output[2]=vec[2]/scalar;
}

Float:GetDistanceBetween(Float:startvec[3],Float:endvec[3])
{
    return SquareRoot((startvec[0]-endvec[0])*(startvec[0]-endvec[0])+(startvec[1]-endvec[1])*(startvec[1]-endvec[1])+(startvec[2]-endvec[2])*(startvec[2]-endvec[2]));
}

public Action:KillPoison(Handle:timer,Handle:hTimer)
{
    if(hTimer!=INVALID_HANDLE)
        CloseHandle(hTimer);
    return Plugin_Stop;
}

public Action:DestroyDataPack(Handle:timer,Handle:datapack)
{
    if(datapack!=INVALID_HANDLE)
        CloseHandle(datapack);
    return Plugin_Stop;
}

SetVelocityVector(client,const Float:velocity[3])
{
    if(client)
    {
        SetEntDataVector(client,BaseVelocityOffset,velocity,true);
        return 1;
    }
    else
        return -1;
}

GetHorizontalVelocity(client,Float:output[3])
{
    if(client)
    {
        output[0]=GetEntDataFloat(client,GetVelocityOffset_0);
        output[1]=GetEntDataFloat(client,GetVelocityOffset_1);
        output[2]=0.0;
        return 1;
    }
    else
    {
        output[0]=0.0;
        output[1]=0.0;
        output[2]=0.0;
        return -1;
    }
}

Freeze(client,bool:freeze,effects)
{
    if(client)
        if(IsClientInGame(client))
        {
            new Float:velocity=GetSpawnSpeed(client);
            if(freeze)
            {
                SetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue", velocity*0.1);
                if(effects)
                    SetColor(client,0,0,255,-1); // Set the player's color
            }
            else
            {
                SetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue", velocity);
                SetColor(client,255,255,255,-1); // Set the player's color
            }
        }
}

SetColor(entity,red,green,blue,alpha)
{
    if(red!=-1)
        SetEntData(entity,ColorOffset,red,1,true);
    if(green!=-1)
        SetEntData(entity,ColorOffset+1,green,1,true);
    if(blue!=-1)
        SetEntData(entity,ColorOffset+2,blue,1,true);
    if(alpha!=-1)
        SetEntData(entity,ColorOffset+3,alpha,1,true);

    SetEntityRenderMode(entity, RENDER_TRANSTEXTURE);
}

PlayLevelupSound(client)
{
    if(client)
    {
        ClientCommand(client,"play buttons/blip2.wav");
        return 1;
    }
    else
        return -1;
}

PlayPurchaseSound(client)
{
    if(client)
    {
        ClientCommand(client,"play weapons/physcannon/physcannon_drop.wav");
        return 1;
    }
    else
        return -1;
}

PlaySellSound(client)
{
    if(client)
    {
        ClientCommand(client,"play buttons/combine_button1.wav");
        return 1;
    }
    else
        return -1;
}

PlayUpgradeErrorSound(client)
{
    if(client)
    {
        ClientCommand(client,"play buttons/combine_button2.wav");
        return 1;
    }
    else
        return -1;
}

PlayResetSound(client)
{
    if(client)
    {
        ClientCommand(client,"play buttons/button5.wav");
        return 1;
    }
    else
        return -1;
}

PlayVampireSound(client)
{
    if(client)
    {
        ClientCommand(client,"play ambient/creatures/leech_bites_loop1.wav");
        return 1;
    }
    else
        return -1;
}

Top10Menu(client)
{
    if(client)
    {
        new Handle:menu_main=CreateMenu(Top10MenuHandle);
        SetMenuPagination(menu_main, MENU_NO_PAGINATION);

        decl String:title[128],String:item[128];
        decl String:Top10[10][2][128];

        Format(title, sizeof(title), "%t", "top10_title");
        SetMenuTitle(menu_main,title);

        new playercount=GetPlayerTop10(Top10,128);
        for(new i=0;i<playercount;i++)
        {
            Format(item, sizeof(item), "%t", "top10_item", Top10[i][0], Top10[i][1]);
            AddMenuItem(menu_main,item,item,ITEMDRAW_DISABLED);
        }

        DisplayMenu(menu_main,client,5);
        return 1;
    }
    else
        return -1;
}

public Top10MenuHandle(Handle:menu_main,MenuAction:action,client,slot)
{
    if(action==MenuAction_Select)
    {
    }
    if(action==MenuAction_End)
        CloseHandle(menu_main);
}

ResetPlayer(client)
{
    if(client)
    {
        // remove player from array
        new vecposi=GetPlayerVectorPosition(client);
        RemoveFromArray(vecPlayers, vecposi);
        // remove player from db
        RemovePlayer(client);
        // reset global upgrade variables
        ResetUpgradeVariables(client);
        PlayResetSound(client);
        // insert player in array
        InitPlayer(client);
        // insert player in db
        LoadPlayerData(client);
        return 1;
    }
    else
        return -1;
}

ResetUpgradeVariables(client)
{
    clientSpawnHealth[client] = 100;
    clientSpawnSpeed[client] = 1.0;
}

/**
 * Returns a list of modules that interlock the given module.
 *
 * @param module        The module to find interlocks for.
 * @param interlocks    A list of modules that interlock the given module.
 *
 * @return              The number of modules that interlock the given module.
 */
stock FindInterlockModules(Module:module, Module:interlocks[MM_DATA_INTERLOCKS])
{
    new dindex = 0;
    new Module:_interlocks[MM_DATA_INTERLOCKS];

    // Loop through all the modules.
    new count = MODULE_COUNT;
    for(new moduleindex = 0; moduleindex < count; moduleindex++)
    {
        ModuleMgr_ReadArray(Module:moduleindex, ModuleData_Interlocks, _interlocks, sizeof(_interlocks));
        for(new _dindex = 0; _dindex < sizeof(_interlocks); _dindex++)
        {
            if(_interlocks[_dindex] == INVALID_MODULE)
                break;

            if(_interlocks[_dindex] == module)
            {
                interlocks[dindex++] = Module:moduleindex;
                break;
            }
        }
    }

    return dindex;
}

bool:IsUpgradeInterlocked(client, Module:module)
{
    if(client)
    {
        new Module:interlocks[MM_DATA_INTERLOCKS];
        new count = FindInterlockModules(module, interlocks);

        for(new dindex = 0; dindex < count; dindex++)
            // check for interlock on module
            if(GetPlayerUpgradeLevel(client,interlocks[dindex]))
                return true;
    }

    return false;
}
